package main.http;

/**
 * Created by hdt3213 on 17/3/27.
 */

import org.json.JSONObject;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.net.URLDecoder;

public class HttpRequest {
	String raw = "";
	String method = "";
	String body = "";
	String path = "";
	String protocol = "";


	HashMap<String, String> headers = new HashMap<String, String>();
	HashMap<String, HttpCookie> cookies = new HashMap<String, HttpCookie>();
	HashMap<String, String> bodyArgs = new HashMap<String, String>();
	HashMap<String, String> queryArgs = new HashMap<String, String>();

	private static boolean isBlank(String line) {
		if (line.trim().length() == 0) {
			return true;
		}
		else {
			return false;
		}
	}

	public HttpRequest() {}

	public HttpRequest(String raw) {
		URLDecoder decoder = new URLDecoder();
		try {
			this.raw = decoder.decode(raw, "UTF-8");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void parse() {
		ArrayList<String> lines = new ArrayList<>();
		String first;
		String content = "";
		int start;

		lines.addAll(Arrays.asList(raw.split("\n")));
		first  = lines.remove(0);

		// parse first
		parseFirstLine(first);

		// parse headers
		start = parseHeaders(lines);

		// parse cookie
		parseCookie();

		// make content
		if (start == -1) {
			return;
		}
		for (int i = start; i < lines.size(); i++) {
			content += lines.get(i);
		}
		// parse content
		parseContent(getHeader("Content-Type"), content);
	}

	private void parseFirstLine(String content) {
		ArrayList<String> pairs = new ArrayList<>();
		ArrayList<String> buf = new ArrayList<>();
		ArrayList<String> items = new ArrayList<>();
		String fullPath;

		// parse first
		items.addAll(Arrays.asList(content.split(" ")));  // Method Path Protocol
		method = items.get(0).trim();
		fullPath = items.get(1).trim();
		protocol = items.get(2).trim();

		// parse query string
		if (items.get(1).indexOf("?") != -1) {
			buf.addAll(Arrays.asList(fullPath.split("\\?")));
			path = buf.remove(0);
			content = buf.remove(0);
			buf.clear();

			// parse query args
			pairs.addAll(Arrays.asList(content.split("&")));
			for (String arg : pairs) {
				buf.addAll(Arrays.asList(arg.split("=")));
				queryArgs.put(buf.get(0), buf.get(1));
				buf.clear();
			}
		}
		else {
			path = items.get(1);
		}
	}

	private int parseHeaders(ArrayList<String> lines) {

		for (int i = 0; i < lines.size(); i++) {
			String line = lines.get(i);

			if (isBlank(line) && i+1 < lines.size()) {
				return i+1;  // first line of content
			}

			int t = line.indexOf(':');
			if ( t == -1) {
				return -1;  // unknown exception
			}
			headers.put(line.substring(0, t), line.substring(t+1).trim());

		}
		return -1;  // has no content
	}

	private void parseCookie() {
		String str = getHeader("Cookie");
		ArrayList<String> pairs = new ArrayList<>();
		ArrayList<String> buf = new ArrayList<>();

		if (str == null) {
			return;
		}

		pairs.addAll(Arrays.asList(str.split(";")));
		for (String arg : pairs) {
			buf.addAll(Arrays.asList(arg.split("=")));
			HttpCookie cookie = new HttpCookie(buf.get(0), buf.get(1));
			cookies.put(buf.get(0), cookie);
			buf.clear();
		}
	}

	private void parseContent(String encode, String content) {
		switch (encode) {
			case "application/x-www-form-urlencoded":
				parseForm(content);
				break;
			case "application/json":
				parseJSON(content);
				break;
		}
	}

	private void parseForm(String content) {
		ArrayList<String> pairs = new ArrayList<>();
		ArrayList<String> buf = new ArrayList<>();

		pairs.addAll(Arrays.asList(content.split("&")));
		for (String arg : pairs) {
			buf.addAll(Arrays.asList(arg.split("=")));
			bodyArgs.put(buf.get(0), buf.get(1));
			buf.clear();
		}
	}

	private void parseJSON(String content) {
		try {
			JSONObject json = new JSONObject(content);
			Iterator iter = json.keys();
			while (iter.hasNext()) {
				String key = (String)iter.next();
				bodyArgs.put(key, json.getString(key));
			}

		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	public String getHeader(String key) {
		return headers.get(key);
	}

	public  HashMap<String, String> getHeaders() {
		return headers;
	}

	public HttpCookie getCookie(String key) {
		return cookies.get(key);
	}

	public HashMap<String, HttpCookie> getCookies() {
		return cookies;
	}

	public String getBodyArg(String key) {
		return bodyArgs.get(key);
	}

	public HashMap<String, String> getBodyArgs() {
		return bodyArgs;
	}

	public String getQueryArg(String key) {
		return queryArgs.get(key);
	}

	public HashMap<String, String> getQueryArgs() {
		return queryArgs;
	}

	public String getPath() {
		return path;
	}

	public String getRaw() {
		return raw;
	}

	public static void main(String[] args) {
	}

}
